// 实现语音识别子服务
#include <brpc/server.h>
#include <butil/logging.h>

#include "asr.hpp"  // 语音识别功能模块
#include "etcd.hpp" // 服务注册模块
#include "logger.hpp"   // 日志模块
#include "speech.pb.h"  // protobuf框架代码

namespace im
{
// 继承SpeechService类，重写rpc业务处理虚函数
class SpeechServiceImpl  : public im::SpeechService
{
public:
    SpeechServiceImpl(const ASRClient::ptr& asr_client)
        : _asr_client(asr_client)
    {}
    virtual void SpeechRecognition(google::protobuf::RpcController* controller,
                                const ::im::SpeechRecognitionReq* request,
                                ::im::SpeechRecognitionRsp* response,
                                ::google::protobuf::Closure* done)
    {
        LOG_DEBUG("收到语音转文字请求!");
        // ClosureGuard功能同智能指针，防止用户忘记调用run函数，超出作用于自动调用
        brpc::ClosureGuard rpc_guard(done);
        
        // 进行语音识别recognize服务调用
        std::string err;
        std::string res = _asr_client->recognize(request->speech_content(), err);
        if (res.empty())
        {
            // 语音识别失败，设置返回值信息
            LOG_ERROR("{} 语音识别失败！", request->request_id());
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg("语音识别失败:" + err);
            return;
        }
        //3. 组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->set_recognition_result(res);
    }
private:
    ASRClient::ptr _asr_client;
};

// 构建RPC服务器
class SpeechServer 
{
public:
    using ptr = std::shared_ptr<SpeechServer>;
private:
    ASRClient::ptr _asr_client; // 封装的语音识别类，需要三个参数
    Registry::ptr _reg_client;  // 封装的etcd服务注册类，需要三个参数
    std::shared_ptr<brpc::Server> _rpc_server; // brpc自己的Server类，需要三个参数
public:
    SpeechServer(const ASRClient::ptr asr_client, const Registry::ptr &reg_client,
                const std::shared_ptr<brpc::Server> &server)
        : _asr_client(asr_client)
        , _reg_client(reg_client)
        , _rpc_server(server)
    {}

    //搭建RPC服务器，并启动服务器
    void start() 
    {
        _rpc_server->RunUntilAskedToQuit();
    }
};
// 帮助创建SpeechServer对象，因为SpeechServer构造函数需要传递很多参数，所以我们采取建造者模式
class SpeechServerBuilder 
{
private:
    ASRClient::ptr _asr_client; 
    Registry::ptr _reg_client;
    std::shared_ptr<brpc::Server> _rpc_server;
public:
    //构造语音识别客户端对象
    void make_asr_object(const std::string &app_id, const std::string &api_key,
                        const std::string &secret_key) 
    {
        _asr_client = std::make_shared<ASRClient>(app_id, api_key, secret_key);
    }
    //用于构造服务注册客户端对象
    void make_reg_object(const std::string &reg_host, const std::string &service_name,
                        const std::string &access_host) 
    {
        _reg_client = std::make_shared<Registry>(reg_host);
        _reg_client->registry(service_name, access_host);
    }
    //构造RPC服务器对象
    void make_rpc_server(uint16_t port, int32_t timeout, uint8_t num_threads) 
    {
        if (!_asr_client) {
            LOG_ERROR("还未初始化语音识别模块！");
            abort();
        }

        _rpc_server = std::make_shared<brpc::Server>();
        // 向服务器对象中新增speech_service服务
        // 需要注意speech_service对象要在最后才能销毁，所以需要申请在堆上
        SpeechServiceImpl* speech_service = new SpeechServiceImpl(_asr_client);
        int ret = _rpc_server->AddService(speech_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
        if (ret == -1) {
            LOG_ERROR("添加Rpc服务失败！");
            abort();
        }
        // 启动brpc服务器
        brpc::ServerOptions options;
        options.idle_timeout_sec = timeout;
        options.num_threads = num_threads;
        ret = _rpc_server->Start(port, &options);
        if (ret == -1) {
            LOG_ERROR("服务启动失败！");
            abort();
        }
    }
    // 返回SpeechServer对象
    SpeechServer::ptr build() 
    {
        if (!_asr_client) {
            LOG_ERROR("还未初始化语音识别模块！");
            abort();
        }
        if (!_reg_client) {
            LOG_ERROR("还未初始化服务注册模块！");
            abort();
        }
        if (!_rpc_server) {
            LOG_ERROR("还未初始化RPC服务器模块！");
            abort();
        }

        SpeechServer::ptr server = std::make_shared<SpeechServer>(_asr_client, _reg_client, _rpc_server);
        return server;
    }
};
}